using System.Collections.Generic;
using CodePlex.UnitTestUtility;
using Xunit;

namespace CodePlex.TfsLibrary.ClientEngine
{
    public class IgnoreListTest
    {
        public class GetIgnores
        {
            [Fact]
            public void DeleteRemovesUpperRecursiveValues()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.EnsurePath(@"C:\Foo\Bar");
                list.FileSystem.EnsurePath(@"C:\Foo\Bar\Baz");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add recursive='true'>foo1</add>
  <add>bar1</add>
</ignore>");
                list.FileSystem.WriteAllText(@"C:\Foo\Bar\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <delete>foo1</delete>
  <add recursive='true'>foo2</add>
  <add>bar2</add>
</ignore>");
                list.FileSystem.WriteAllText(@"C:\Foo\Bar\Baz\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add recursive='true'>foo3</add>
  <add>bar3</add>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo\Bar\Baz"));

                Assert.Equal(3, results.Count);
                Assert.Contains("foo2", results);
                Assert.Contains("foo3", results);
                Assert.Contains("bar3", results);
            }

            [Fact]
            public void EmptyIgnoreList()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo"));

                Assert.Equal(0, results.Count);
            }

            [Fact]
            public void InheritsRecursiveAdds()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.EnsurePath(@"C:\Foo\Bar");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add recursive='true'>foo</add>
  <add>bar</add>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo\Bar"));

                Assert.Equal(1, results.Count);
                Assert.Contains("foo", results);
            }

            [Fact]
            public void InvalidIgnoreList()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"<duh></duh>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo"));

                Assert.Equal(0, results.Count);
            }

            [Fact]
            public void ItemsAreCaseInsensitive()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.EnsurePath(@"C:\Foo\Bar");
                list.FileSystem.EnsurePath(@"C:\Foo\Bar\Baz");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add recursive='true'>foo1</add>
  <add>bar1</add>
</ignore>");
                list.FileSystem.WriteAllText(@"C:\Foo\Bar\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <delete>FoO1</delete>
  <add recursive='true'>foo2</add>
  <add>bar2</add>
</ignore>");
                list.FileSystem.WriteAllText(@"C:\Foo\Bar\Baz\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add recursive='true'>foo3</add>
  <add>bar3</add>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo\Bar\Baz"));

                Assert.Equal(3, results.Count);
                Assert.Contains("foo2", results);
                Assert.Contains("foo3", results);
                Assert.Contains("bar3", results);
            }

            [Fact]
            public void MultipleAdd()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add>foo</add>
  <add>bar</add>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo"));

                Assert.Equal(2, results.Count);
                Assert.Contains("foo", results);
                Assert.Contains("bar", results);
            }

            [Fact]
            public void SingleAdd()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add>foo</add>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo"));

                Assert.Equal(1, results.Count);
                Assert.Contains("foo", results);
            }

            [Fact]
            public void SingleDelete()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <delete>foo</delete>
</ignore>");

                List<string> results = new List<string>(list.GetIgnores(@"C:\Foo"));

                Assert.Equal(0, results.Count);
            }

            // Duplicates
        }

        public class IsIgnored
        {
            [Fact]
            public void MultipleAdd()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add>foo</add>
  <add>bar</add>
</ignore>");

                bool isIgnored = list.IsIgnored(@"C:\Foo\foo");

                Assert.True(isIgnored);
            }

            [Fact]
            public void SingleAdd()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add>foo</add>
</ignore>");

                bool isIgnored = list.IsIgnored(@"C:\Foo\foo");

                Assert.True(isIgnored);
            }

            [Fact]
            public void SupportForWildcards()
            {
                TestableIgnoreList list = TestableIgnoreList.Create();
                list.IgnoreFilename = ".tfs-ignore";
                list.FileSystem.EnsurePath(@"C:\Foo");
                list.FileSystem.WriteAllText(@"C:\Foo\.tfs-ignore", @"
<ignore xmlns='http://www.codeplex.com/schema/IgnoreListSchema-1.0.xsd'>
  <add>foo*</add>
</ignore>");

                Assert.True(list.IsIgnored(@"C:\Foo\Foobar"));
                Assert.False(list.IsIgnored(@"C:\Foo\barfoo"));
            }
        }

        class TestableIgnoreList : IgnoreList
        {
            public readonly MockFileSystem FileSystem;

            TestableIgnoreList(MockFileSystem fileSystem)
                : base(fileSystem)
            {
                FileSystem = fileSystem;
            }

            public static TestableIgnoreList Create()
            {
                return new TestableIgnoreList(new MockFileSystem());
            }
        }
    }
}